package com.sino.operation.service.basic;

import com.alibaba.fastjson.JSONArray;
import com.sino.operation.commons.commonEnum.PostEgCnEnum;
import com.sino.operation.commons.commonEnum.TaskState;
import com.sino.operation.entity.BizTaskPool;
import com.sino.operation.entity.BizTranslist;
import com.sino.operation.entity.SysAbMessage;
import com.sino.operation.entity.SysDict;
import com.sino.operation.mapper.BizTranslistMapper;
import com.sino.operation.mapper.SysAbMessageMapper;
import com.sino.operation.mapper.SysDictMapper;
import com.sino.operation.service.BizTranslistService;
import com.sino.operation.service.SysDictService;
import com.sino.operation.service.impl.BizTaskPoolServiceImpl;
import com.sino.operation.service.impl.SysDictServiceImpl;
import com.sino.operation.util.ReflectExecuteUtil;
import com.sino.operation.vo.inner.ResponseHead;
import com.sino.operation.vo.inner.ResponseMessage;
import com.sino.operation.websocket.MyWebsocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Wrapper;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Title: WorkFlowService
 * @Description: 工作流服务
 * @Author dengls
 * @date 2021/10/13 16:47
 */
@Slf4j
@Service
public class WorkFlowService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private BizTaskPoolServiceImpl bizTaskPoolService;
    @Autowired
    private RedisTaskUserService redisTaskUserService;
    @Autowired
    private SysDictServiceImpl sysDictService;
    @Autowired(required = false)
    private BizTranslistMapper bizTranslistMapper;
    @Autowired(required = false)
    private SysAbMessageMapper sysAbMessageMapper;
    /*key  流水号+岗位号，value 柜员号*/
    public static Map<String, String> TaskHashMap = new HashMap<>();

    /**
     * 处理任务
     *
     * @param flowId         工作流id
     * @param taskId         任务id
     * @param journalNo      流水号
     * @param transCode      交易类型
     * @param tellerPostName 岗位名
     */
    public void handlerTask(String flowId, String taskId, String journalNo, String transCode, String tellerPostName) throws Exception {
        ResponseMessage responseMessage = new ResponseMessage();
        ResponseHead responseHead = new ResponseHead();
        Map<String, String> map = bizTranslistMapper.selectMapById(journalNo);
        SysAbMessage sysAbMessage = sysAbMessageMapper.selectById(journalNo);
        SysDict sysDict = sysDictService.selectDictByName(tellerPostName);
        String tellerPost = sysDict.getDictValue();
        String methodName = PostEgCnEnum.getValue(tellerPost);
        Object result = ReflectExecuteUtil.executeGetTask("Exec_" + transCode, "execute" + methodName + "Task", journalNo, sysAbMessage);
        responseHead.setTranName(map.get("TRANS_NAME"));
        responseHead.setImageId(map.get("IMAGE_ID"));
        responseHead.setTranCode(transCode);
        responseHead.setTaskId(taskId);
        responseHead.setJournalNo(journalNo);
        responseHead.setNodeName(tellerPostName);
        responseMessage.setResponseHead(responseHead);
        responseMessage.setBody(result);
        BizTaskPool bizTaskPool = new BizTaskPool();
        bizTaskPool.setFlowId(flowId);
        bizTaskPool.setJournalNo(journalNo);
        bizTaskPool.setTaskId(taskId);
        bizTaskPool.setReceiveTime(LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE));
        bizTaskPool.setNodeName(tellerPostName);
        bizTaskPool.setTransCode(transCode);
        bizTaskPool.setTellerPost(tellerPost);
        String tellerCode = this.putTask(tellerPost, transCode, responseMessage);
        String taskKey = journalNo + "-" + tellerPost;
        if ("false".equals(tellerCode)) {
            //任务没有推送出去
            if (TaskHashMap.containsKey(taskKey)) {
                //任务map包含相同流水号，说明为第二次进入，且第一笔推送成功。将第一笔获取人员设置为第二笔不能获取人员
                bizTaskPool.setNotTellerCode(TaskHashMap.get(taskKey));
            } else {
                //不包含，说明为第一次进入
                bizTaskPool.setTaskState(TaskState.TaskState1.getValue());
            }
        } else {
            //任务推送出去，回执回来就是推送柜员号
            bizTaskPool.setTaskState(TaskState.TaskState3.getValue());
            bizTaskPool.setTellerCode(tellerCode);
            if (TaskHashMap.containsKey(taskKey)) {
                //任务map包含相同流水号，说明为第二次进入，且第一笔推送成功。将第一笔获取人员设置为第二笔不能获取人员
                bizTaskPool.setNotTellerCode(TaskHashMap.get(taskKey));
                //查询第一笔数据
                List<BizTaskPool> bizTaskPools = bizTaskPoolService.selectList(journalNo);
                if (bizTaskPools.size() == 1) {
                    //设置当前柜员为第一笔不能获取人
                    BizTaskPool one = bizTaskPools.get(0);
                    one.setNotTellerCode(tellerCode);
                    bizTaskPoolService.saveOrUpdate(one);
                }
            } else {
                //不包含，说明为第一次进入，将人员存入缓存信息中
                TaskHashMap.put(taskKey, tellerCode);
            }
            //移除Redis中的用户信息
            redisTaskUserService.removeUserData(tellerPost, tellerCode);
        }
        bizTaskPoolService.save(bizTaskPool);
    }

    /**
     * 任务推送
     *
     * @param tellerPost 岗位号
     * @param transType  交易类型
     * @param str        报文
     * @return
     */
    private String putTask(String tellerPost, String transType, ResponseMessage str) {
        SetOperations<String, String> ops = stringRedisTemplate.opsForSet();
        String key = "commonData-" + tellerPost + "-" + transType;
        Long dataSize = ops.size(key);
        if (dataSize > 0) {
            String tellerCode = ops.pop(key);
            //调用websocket发送任务
            String taskDtoString = JSONArray.toJSONString(str);
            try {
                MyWebsocketServer.sendTask(taskDtoString, tellerCode);
            } catch (Exception e) {
                //推送失败，可能是websocket部分出现问题，柜员退出websocket连接并没有断开
                //移除Redis中断开的用户信息
                redisTaskUserService.removeUserData(tellerPost, tellerCode);
                //判断是否存在其它同岗位柜员连接，尝试推送其它同岗位柜员
                if (ops.size(key) > 0) {
                    return putTask(tellerPost, transType, str);
                }
                return "false";
            }
            return tellerCode;
        } else {
            return "false";
        }
    }
}
